#include "SRTF_Scheduler.h"
#include <iostream>
#include <vector>

using namespace std;

SRTF_Scheduler::SRTF_Scheduler()
{
}

void SRTF_Scheduler::sortProcesses()
{
	vector<Process>::iterator end, positionOne, positionTwo;
	bool swapped = true;

	end = processList.end();

	do
	{
		swapped = false;
		positionTwo = ++processList.begin();
		for(positionOne = processList.begin(); positionTwo != end; positionOne++, positionTwo++)
		{
			if(compareArrivalTime(positionOne, positionTwo))
			{
				swap(*positionOne, *positionTwo);
				swapped = true;
			}
		}
	}while(swapped);
}

bool SRTF_Scheduler::compareArrivalTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo)
{
	return (*positionOne).getArrivalTIme() > (*positionTwo).getArrivalTIme();
}


bool SRTF_Scheduler::needSwitched(vector<Process>::iterator index, int arrival_difference)
{
	return (arrival_difference - (*index).getCPU_Burst() < 0) && (*(index + 1)).getCPU_Burst() < (*index).getCPU_Burst() - arrival_difference;
}


void SRTF_Scheduler::sortByBurstTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo, vector<Process> &queue)
{
	vector<Process>::iterator end, posOne, posTwo;
	bool swapped;

	posOne = positionOne;
	posTwo = (posOne + 1);

	do
	{
		cout << "ive been called ..... finally!\n";
		swapped = false;
		for(posOne = positionOne; posTwo != positionTwo; posOne++, posTwo++)
		{
			if(compareBurstTime(positionOne, positionTwo))
			{
				swap(*positionOne, *positionTwo);
				swapped = true;
			}
		}
	}while(swapped);
}

bool SRTF_Scheduler::compareBurstTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo)
{
	return (*positionOne).getCPU_Burst() > (*positionTwo).getCPU_Burst();
}

void SRTF_Scheduler::assignValuesToProcessList(Process temp)
{
	vector<Process>::iterator location;
	location = processList.begin();
	findProcessID(location, temp.getProcessID());

	(*location).setEndTime(temp.getEndTime());
	(*location).setStartTime(temp.getStartTime());
	(*location).setFinished();

}

void SRTF_Scheduler::findProcessID(vector<Process>::iterator &location, int processID)
{
	while((*location).getProcessID() != processID)
		location++;
}


void SRTF_Scheduler::runScheduler()
{
	vector<Process>::iterator index, end, tempProcessListItr, ready_queueItr;
	vector<Process> ready_queue, tempProcessList;
	int endTime = 0, arrivalTime, arrival_difference;
	Process temp(0,0,0);

	//needed to ensure there wont be a problem with resource allocation of the vector
	//during run-time. 
	ready_queue.reserve(1000);
	sortProcesses();

	tempProcessList = processList;

	ready_queue.push_back(tempProcessList.front());
	tempProcessList.erase(tempProcessList.begin());
	index = tempProcessList.begin();

	do
	{

		arrival_difference = (ready_queue.front()).getArrivalTIme() - (*index).getArrivalTIme();

		//find a candidate for switching
		while((index + 1) != tempProcessList.end() && !needSwitched(index, arrival_difference) && (*index).getArrivalTIme() < endTime)
		{
			index++;
		}

		//no candidate for switching was found, so the process will finish its run
		if((index + 1) == tempProcessList.end() || (*index).getArrivalTIme() > endTime)
		{
			(*(ready_queue.begin())).setStartTime((*(ready_queue.begin())).getArrivalTIme());
			(*(ready_queue.begin())).setEndTime((*(ready_queue.begin())).getArrivalTIme() + (*(ready_queue.begin())).getCPU_Burst());
			endTime = (*(ready_queue.begin())).getEndTime();
			assignValuesToProcessList(ready_queue.front());
			ready_queue.erase(ready_queue.begin());
		}
		else
		{ //candidate was found for context switch

			if(!(*(ready_queue.begin())).wasProcessed())
			{
				(*(ready_queue.begin())).setStartTime(endTime);
			}
			else
				(*(ready_queue.begin())).setProcessed();

			
			(*(ready_queue.begin())).setEndTime(endTime + arrival_difference);
			(*(ready_queue.begin())).setCPU_Burst((*(ready_queue.begin())).getCPU_Burst() - arrival_difference);
			endTime = (*(ready_queue.begin())).getEndTime();
			ready_queue.push_back(ready_queue.front());
			ready_queue.erase(ready_queue.begin());
			ready_queue.insert((ready_queue.begin()), *index);
		}

		ready_queue.push_back(tempProcessList.front());
		tempProcessList.erase(tempProcessList.begin());
		index = tempProcessList.begin();


	}while(ready_queue.size() != 0);

	for(vector<Process>::iterator begin = processList.begin(); begin != processList.end(); begin++)
		cout << (*begin).getArrivalTIme() << "     " << (*begin).getCPU_Burst() << endl;
}
		


